/**
 * 节流钩子函数
 * @param fn 要节流的函数
 * @param delay 延迟时间，默认为200毫秒
 * @param trailing 是否在延迟时间结束后执行最后一次函数，默认为true
 * @returns
 */
export function useThrottleFn<T extends Function>(
  // 要节流的函数
  fn: T,
  // 节流时间，默认为200毫秒
  delay = 200,
  // 是否在节流时间结束后执行最后一次函数，默认为true
  trailing = true
) {
  // 如果节流时间为0，则直接返回原函数
  if (delay <= 0) return fn
  // 上一次执行的时间
  let lastExec = 0,
    // 上一次执行的this
    lastThis: any,
    // 上一次执行的参数
    lastArgs: any[]
  // 定时器
  let timer: ReturnType<typeof setTimeout> | undefined

  // 清除定时器
  function clear() {
    if (timer) {
      clearTimeout(timer)
      timer = void 0
    }
  }

  // 定时器回调函数
  function timeoutCallback() {
    clear()
    fn.apply(lastThis, lastArgs)
  }

  // 包装函数
  function wrapper(this: any, ...args: any[]) {
    // 计算距离上一次执行的时间
    const elapsed = Date.now() - lastExec
    clear()
    // 如果距离上一次执行的时间大于节流时间，则执行函数
    if (elapsed > delay) {
      lastExec = Date.now()
      fn.apply(this, args)
      // 如果距离上一次执行的时间小于节流时间，且trailing为true，则将参数和this保存，并在节流时间结束后执行最后一次函数
    } else if (trailing) {
      lastArgs = args
      lastThis = this
      timer = setTimeout(timeoutCallback, delay)
    }
  }

  // 返回包装函数
  return wrapper as any as T
}
